package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.EamArtifact;
import com.uinnova.product.eam.comm.model.es.EamArtifactElement;
import com.uinnova.product.eam.model.EamArtifactCiVo;
import com.uinnova.product.eam.model.EamArtifactElementVo;
import com.uinnova.product.eam.model.diagram.DiagramNodeLinkInfo;
import com.uinnova.product.eam.model.dto.ArtifactElementDto;
import com.uinnova.product.eam.model.dto.EamArtifactElementDto;
import com.uinnova.product.eam.model.dto.ElementDto;
import com.uinnova.product.eam.model.enums.ArtifactType;
import com.uinnova.product.eam.model.vo.CiClassRltVo;
import com.uinnova.product.eam.service.IEamArtifactColumnSvc;
import com.uinnova.product.eam.service.IEamCIClassApiSvc;
import com.uinnova.product.eam.service.es.EamArtifactDao;
import com.uinnova.product.eam.service.es.EamArtifactElementDao;
import com.uinnova.product.eam.service.utils.VisualModelUtils;
import com.uinnova.product.vmdb.comm.model.ci.CcCiClass;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.ESVisualModel;
import com.uino.bean.permission.base.SysUser;
import com.uino.dao.cmdb.ESRltClassSvc;
import com.uino.dao.cmdb.ESVisualModelSvc;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 新建制品分栏信息-实现类
 * @author : wangchunlei
 */
@Slf4j
@Service
public class EamArtifactColumnSvcImpl implements IEamArtifactColumnSvc {

    private static final String ID = "artifactId";

    @Autowired
    private EamArtifactElementDao elementDao;
    @Autowired
    private EamArtifactDao eamArtifactDao;
    @Value("${http.resource.space}")
    private String rsmSlaveRoot;
    @Value("${local.resource.space}")
    private String localRsmPath;
    @Autowired
    private ESVisualModelSvc visualModelSvc;
    @Resource
    private IEamCIClassApiSvc ciClassApiSvc;
    @Autowired
    private ESRltClassSvc rltClassSvc;
    @Resource
    private ESDiagramApiClient diagramApiClient;

    @Override
    public Integer saveOrUpdate(ArtifactElementDto dto) {
        //删除分栏
        if (CollectionUtils.isNotEmpty(dto.getDeleteId())) {
            elementDao.deleteByIds(dto.getDeleteId());
        }
        List<EamArtifactElementDto> saveList = dto.getElements();
        //添加或者修改
        if (CollectionUtils.isEmpty(saveList)) {
            return 1;
        }
        List<EamArtifactElement> elementList = new ArrayList<>();
        EamArtifact artifact = eamArtifactDao.getById(saveList.get(0).getArtifactId());
        List<EamArtifactElement> elements = this.selectElements(artifact.getId(), null);
        if(!BinaryUtils.isEmpty(elements)){
            List<Long>  elementIds = elements.stream().map(EamArtifactElement::getId).collect(Collectors.toList());
            //取出保存参数里的数据；id
            List<Long> paramIds = saveList.stream().map(EamArtifactElementDto::getId).filter(Objects::nonNull).collect(Collectors.toList());
            //如果不为空，就删掉
            elementIds.removeAll(paramIds);
            if(!BinaryUtils.isEmpty(elementIds)){
                elementDao.deleteByIds(elementIds);
            }
        }
        for (EamArtifactElementDto element : saveList) {
            EamArtifactElement copy = EamUtil.copy(element, EamArtifactElement.class);
            if (CollectionUtils.isNotEmpty(copy.getElements())) {
                List<String> saveElement = new ArrayList<>();
                for (String each : copy.getElements()) {
                    String replaceElement = each.replaceAll(rsmSlaveRoot, "");
                    JSONObject json = JSON.parseObject(replaceElement);
                    if(element.getType() == ArtifactType.CI_TYPE.val() && BinaryUtils.isEmpty(json.getString("id"))){
                        json.put("id", "QuickEA_"+ESUtil.getUUID());
                    }
                    saveElement.add(json.toJSONString());
                }
                copy.setElements(saveElement);
            }
            copy.setCreateTime(BinaryUtils.getNumberDateTime());
            copy.setModifyTime(BinaryUtils.getNumberDateTime());
            if (BinaryUtils.isEmpty(copy.getId())) {
                copy.setId(ESUtil.getUUID());
            }
            elementList.add(copy);
        }
        artifact.setModifyTime(BinaryUtils.getNumberDateTime());
        eamArtifactDao.saveOrUpdate(artifact);
        return elementDao.saveOrUpdateBatch(elementList);
    }

    @Override
    public Integer saveOrUpdateBatch(List<EamArtifactElement> elements) {
        return elementDao.saveOrUpdateBatch(elements);
    }

    @Override
    public List<EamArtifactElementVo> queryByArtifactId(Long artifactId, List<Integer> types) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery(ID, artifactId));
        if(CollectionUtils.isNotEmpty(types)){
            query.must(QueryBuilders.termsQuery("type", types));
        }
        List<EamArtifactElement> list = elementDao.getListByQuery(query);
        if(CollectionUtils.isEmpty(list)){
            return new ArrayList<>();
        }

        List<Long> classIds = new ArrayList<>();
        for (EamArtifactElement each : list) {
            for (String element : each.getElements()) {
                JSONObject json = JSON.parseObject(element);
                if ("class".equals(json.getString("type"))) {
                    classIds.add(json.getLong("id"));
                }
            }
        }
        Map<Long, String> classMap = new HashMap<>();
        if (!BinaryUtils.isEmpty(classIds)) {
            List<ESCIClassInfo> classList = ciClassApiSvc.selectCiClassByIds(classIds);
            classMap = classList.stream().collect(Collectors.toMap(ESCIClassInfo::getId, CcCiClass::getIcon, (k1, k2) -> k1));
        }
        List<EamArtifactElementVo> result = EamUtil.copy(list, EamArtifactElementVo.class);
        for (EamArtifactElementVo each : result) {
            if (BinaryUtils.isEmpty(each.getElements())) {
                continue;
            }
            if(each.getType().equals(ArtifactType.CI_TYPE.val())
                    || each.getType().equals(ArtifactType.ASSET_TYPE.val())
                    || each.getType().equals(ArtifactType.DISTINGUISH_TYPE.val())){
                each.setElements(replaceCiClassIconAndShapeImage(each.getElements(), classMap));
            }else if(each.getType().equals(ArtifactType.RLT_TYPE.val())){
                each.setElements(replaceRltClassIcon(each.getElements(), classMap));
            }
        }
        return result;
    }

    /**
     * 替换关系数据中分类icon
     * @param elements 制品分栏
     * @param classMap 分类icon map
     * @return 替换后的制品分栏
     */
    private List<String> replaceRltClassIcon(List<String> elements, Map<Long, String> classMap){
        List<String> result = new ArrayList<>();
        for (String element : elements) {
            JSONObject json = JSON.parseObject(element);
            JSONObject sourceCiInfo = json.getJSONObject("sourceCiInfo");
            JSONObject targetCiInfo = json.getJSONObject("targetCiInfo");
            if(sourceCiInfo != null){
                Long id = sourceCiInfo.getLong("id");
                sourceCiInfo.put("icon", classMap.get(id));
            }
            if(targetCiInfo != null){
                Long id = targetCiInfo.getLong("id");
                targetCiInfo.put("icon", classMap.get(id));
            }
            result.add(JSON.toJSONString(json));
        }
        return result;
    }

    /**
     * 替换ci分类icon和形状image
     * @param elements 制品分栏
     * @param classMap 分类icon map
     * @return 替换后的制品分栏
     */
    private List<String> replaceCiClassIconAndShapeImage(List<String> elements, Map<Long, String> classMap){
        List<String> result = new ArrayList<>();
        for (String element : elements) {
            JSONObject json = JSON.parseObject(element);
            //优先处理形状
            if (StringUtils.isNotBlank(json.getString("nodeData"))) {
                JSONObject nodeData = JSON.parseObject(json.getString("nodeData"));
                String image = nodeData.getString("image");
                if (StringUtils.isNotBlank(image) && image.startsWith("/")) {
                    image = rsmSlaveRoot + image;
                    nodeData.put("image", image);
                    json.put("nodeData", nodeData);
                }
                String icon = json.getString("icon");
                if (StringUtils.isNotBlank(icon) && icon.startsWith("/")) {
                    icon = rsmSlaveRoot + icon;
                    json.put("icon", icon);
                }
                String url = json.getString("url");
                if (StringUtils.isNotBlank(url) && url.startsWith("/")) {
                    url = rsmSlaveRoot + url;
                    json.put("url", url);
                }
                result.add(JSON.toJSONString(json));
                continue;
            }
            String classIcon = "";
            if("class".equals(json.getString("type")) && !BinaryUtils.isEmpty(json.getLong("id"))){
                classIcon = classMap.getOrDefault(json.getLong("id"), "");
            }
            String icon = json.getString("icon");
            if (!BinaryUtils.isEmpty(icon)) {
                File file = new File(localRsmPath + icon);
                if(file.exists()){
                    json.put("icon", rsmSlaveRoot + icon);
                }else{
                    json.put("icon", classIcon);
                }
            }
            String viewIcon = json.getString("viewIcon");
            if (!BinaryUtils.isEmpty(viewIcon)) {
                json.put("viewIcon", rsmSlaveRoot + viewIcon);
                File file = new File(localRsmPath + viewIcon);
                if(file.exists()){
                    json.put("viewIcon", rsmSlaveRoot + viewIcon);
                }else{
                    json.put("viewIcon", classIcon);
                }
            }
            result.add(JSON.toJSONString(json));
        }
        return result;
    }

    @Override
    public List<EamArtifactElementVo> queryAllColumns(ElementDto dto) {
        EamArtifact artifact = eamArtifactDao.getById(dto.getArtifactId());
        List<Integer> type = BinaryUtils.isEmpty(dto.getType())?null: Lists.newArrayList(dto.getType());
        List<EamArtifactElementVo> result = this.queryByArtifactId(dto.getArtifactId(), type);
        for (EamArtifactElementVo each : result) {
            each.setTypeClassification(artifact.getTypeClassification());
        }
        return result;
    }

    @Override
    public Map<Long, List<EamArtifactElementVo>> queryAllColumnsByIds(List<Long> artifactIds) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery(ID, artifactIds));
        List<EamArtifactElement> eamArtifactElements = elementDao.getListByQuery(query);
        Map<Long, List<EamArtifactElement>> eamArtifactElementMap = eamArtifactElements.stream().collect(Collectors.groupingBy(EamArtifactElement::getArtifactId));
        Map<Long, List<EamArtifactElementVo>> data = new HashMap<>();
        for (Long artifactId : eamArtifactElementMap.keySet()) {
            List<EamArtifactElementVo> result = EamUtil.copy(eamArtifactElementMap.get(artifactId), EamArtifactElementVo.class, (s, t) -> {
                List<String> elements = t.getElements();
                if (!BinaryUtils.isEmpty(elements)) {
                    List<String> elementsNew = new ArrayList<>(elements.size());
                    for (String element : elements) {
                        JSONObject productEleJson = JSON.parseObject(element);
                        if (productEleJson.containsKey("icon") && !BinaryUtils.isEmpty(productEleJson.getString("icon"))) {
                            productEleJson.put("icon", rsmSlaveRoot + productEleJson.getString("icon"));
                        }
                        if (productEleJson.containsKey("viewIcon") && !BinaryUtils.isEmpty(productEleJson.getString("viewIcon"))) {
                            productEleJson.put("viewIcon", rsmSlaveRoot + productEleJson.getString("viewIcon"));
                        }
                        elementsNew.add(JSON.toJSONString(productEleJson));
                    }
                    t.setElements(elementsNew);
                }
            });
            data.put(artifactId, result);
        }
        return data;
    }


    @Override
    public List<CiClassRltVo> queryRelationFromObjects(List<Long> ciClassIds) {
        if(BinaryUtils.isEmpty(ciClassIds)){
            return Collections.emptyList();
        }
        Long domainId = SysUtil.getCurrentUserInfo().getDomainId();
        //制品的ci分类集合
        List<ESCIClassInfo> classInfoList = ciClassApiSvc.selectCiClassByIds(ciClassIds);
        if(BinaryUtils.isEmpty(classInfoList)){
            return Collections.emptyList();
        }
        Map<Long, ESCIClassInfo> classMap = classInfoList.stream().collect(Collectors.toMap(CcCiClass::getId, each -> each, (key1, key2) -> key2));
        //拿到所有的关系分类
        List<CcCiClassInfo> rltCls = rltClassSvc.queryAllClasses(domainId);
        if (BinaryUtils.isEmpty(rltCls)) {
            return Collections.emptyList();
        }
        Map<Long, CcCiClassInfo> rltClsMap = rltCls.stream().collect(Collectors.toMap(ciClass -> ciClass.getCiClass().getId(), each -> each,(key1, key2) -> key2));
        ESVisualModel model = visualModelSvc.getEnableModel(domainId);
        if(BinaryUtils.isEmpty(model) || BinaryUtils.isEmpty(model.getJson())){
            return Collections.emptyList();
        }
        List<CiClassRltVo> result = new ArrayList<>();
        Set<String> distinctSet = new HashSet<>();
        List<DiagramNodeLinkInfo> rltLinkList = VisualModelUtils.getRltClassIds(model);
        for (DiagramNodeLinkInfo link : rltLinkList) {
            if(distinctSet.contains(link.getLinkKey())){
                continue;
            }
            distinctSet.add(link.getLinkKey());
            //拿到源端信息，目标端信息，关系信息
            CiClassRltVo ciClassRltVo = new CiClassRltVo();
            ESCIClassInfo sourceCi = classMap.get(link.getSourceId());
            if(sourceCi == null){
                continue;
            }
            sourceCi.setAttrDefs(null);
            sourceCi.setCcAttrDefs(null);
            String sourceIcon = sourceCi.getIcon();
            if (sourceIcon != null && !sourceIcon.startsWith(rsmSlaveRoot)) {
                sourceIcon = rsmSlaveRoot + sourceIcon;
                sourceCi.setIcon(sourceIcon);
            }
            ciClassRltVo.setSourceCiInfo(sourceCi);
            ESCIClassInfo targetCi = classMap.get(link.getTargetId());
            if(targetCi == null){
                continue;
            }
            targetCi.setAttrDefs(null);
            targetCi.setCcAttrDefs(null);
            String targetIcon = targetCi.getIcon();
            if (targetIcon != null && !targetIcon.startsWith(rsmSlaveRoot)) {
                targetIcon = rsmSlaveRoot + targetIcon;
                targetCi.setIcon(targetIcon);
            }
            ciClassRltVo.setTargetCiInfo(targetCi);
            ciClassRltVo.setRltClassInfo(rltClsMap.get(link.getLinkId()));
            ciClassRltVo.setViewName(ciClassRltVo.getRltClassInfo().getCiClass().getClassName());
            result.add(ciClassRltVo);
        }
        return result;
    }

    @Override
    public Page<ESDiagram> queryTemplateByArtifactId(Long artifactId, Integer pageNum, Integer pageSize, String like) {
        SysUser currentUserInfo = SysUtil.getCurrentUserInfo();
        BoolQueryBuilder diagramQuery = QueryBuilders.boolQuery();
        diagramQuery.must(QueryBuilders.termQuery("diagramType", 3));
        if (!BinaryUtils.isEmpty(like)) {
            diagramQuery.must(QueryBuilders.termQuery("name.keyword", like));
        }
        diagramQuery.must(QueryBuilders.termQuery("status", 1));
        diagramQuery.must(QueryBuilders.termQuery("dataStatus", 1));
        diagramQuery.must(QueryBuilders.termQuery("domainId", currentUserInfo.getDomainId()));
        if (BinaryUtils.isEmpty(artifactId) || artifactId.equals(0L)) {
            // 空白视图前端传参为0， 需要查询所有数据
            return diagramApiClient.selectListByQuery(pageNum, pageSize, diagramQuery);
        }
        //查询制品配置的模板
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery(ID, artifactId));
        boolQueryBuilder.must(QueryBuilders.termQuery("type", 4));
        List<EamArtifactElement> artifactElementList = elementDao.getListByQuery(boolQueryBuilder);
        if (CollectionUtils.isEmpty(artifactElementList)) {
            return new Page<>(pageNum, pageSize, 0L, 0L , new ArrayList<>());
        }
        if (artifactElementList.size() > 1) {
            throw new ServiceException("制品模板配置不唯一！");
        }
        EamArtifactElement eamArtifactElement = artifactElementList.get(0);
        List<String> elements = eamArtifactElement.getElements();
        if (CollectionUtils.isEmpty(elements)) {
            return new Page<>(pageNum, pageSize, 0L, 0L , new ArrayList<>());
        }
        String defaultDiagram = "";
        Set<String> diagramIds = new HashSet<>();
        for (String element : elements) {
            JSONObject jsonObject = JSON.parseObject(element);
            if(!jsonObject.containsKey("diagramId")){
                continue;
            }
            String diagramId = jsonObject.getString("diagramId");
            diagramIds.add(diagramId);
            if (jsonObject.containsKey("default") && jsonObject.getBoolean("default")) {
                defaultDiagram = diagramId;
            }
        }
        //查询所有模板信息
        diagramQuery.must(QueryBuilders.termsQuery("dEnergy.keyword", diagramIds));
        Page<ESDiagram> diagramPage = diagramApiClient.selectListByQuery(pageNum, pageSize, diagramQuery);
        if (CollectionUtils.isNotEmpty(diagramPage.getData()) && !BinaryUtils.isEmpty(defaultDiagram)) {
            //设置该视图为制品中的默认模板
            for (ESDiagram each : diagramPage.getData()) {
                if(each.getDEnergy().equals(defaultDiagram)){
                    each.setTemType(3);
                }
            }
        }
        return diagramPage;
    }

    @Override
    public Integer refreshData() {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.mustNot(QueryBuilders.existsQuery("type"));
        List<EamArtifactElement> list = elementDao.getListByQuery(queryBuilder);
        List<EamArtifactElement> updateList = new ArrayList<>();
        for(EamArtifactElement element : list){
            if(BinaryUtils.isEmpty(element.getType())){
                element.setType(ArtifactType.CI_TYPE.val());
                updateList.add(element);
            }
        }
        elementDao.saveOrUpdateBatch(updateList);
        return 1;
    }

    @Override
    public Map<Long, List<EamArtifactElement>> queryByIdsAndType(List<Long> artifactIds, List<Integer> types) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery(ID, artifactIds));
        if(!BinaryUtils.isEmpty(types)){
            query.must(QueryBuilders.termsQuery("type", types));
        }
        List<EamArtifactElement> listByQuery = elementDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(listByQuery)) {
            return new HashMap<>();
        }
        return listByQuery.stream().collect(Collectors.groupingBy(EamArtifactElement::getArtifactId));
    }

    @Override
    public List<Map<String, Object>> getArchSystemList(Long artifactId) {
        List<EamArtifactElementVo> artifactNodes = this.queryByArtifactId(artifactId, Collections.singletonList(ArtifactType.ASSET_TYPE.val()));
        if (BinaryUtils.isEmpty(artifactNodes)) {
            return Collections.emptyList();
        }
        List<EamArtifactCiVo> elements = artifactNodes.stream().map(EamArtifactElementVo::getElementCiObj).flatMap(Collection::stream).collect(Collectors.toList());
        return elements.stream().filter(EamArtifactCiVo::getViewFlag).map(s -> JSON.parseObject(JSON.toJSONString(s)).getInnerMap()).collect(Collectors.toList());
    }

    /**
     * 查询制品分栏信息(未做icon处理)
     * @param artifactId 制品id
     * @param type 分栏类型
     * @return 制品分栏信息
     */
    public List<EamArtifactElement> selectElements(Long artifactId, Integer type){
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery(ID, artifactId));
        if(!BinaryUtils.isEmpty(type)) {
            query.must(QueryBuilders.termQuery("type", type));
        }
        return elementDao.getListByQuery(query);
    }
}




